//
//  MoyaRequest.swift
//  Intersection
//
//  Created by 我骑着蜗牛走天下 on 2025/3/4.
//


import Moya
import SmartCodable
import Foundation

// MARK: - 显示和后处理协议

///  HUD显示 和 请求返回数据的请求后处理
public protocol RequestAndShow {
//    var showLoading: Bool { get }
//    var showError: Bool { get }
    
    /// 显示提示
    func showMsg(msg:String)
    /// 显示错误提示
    func showErrorMsg(code:Int,msg:String)
    /// 显示加载
    func showLoading()
    /// 隐藏加载
    func hideLoading()
    /// 登录过期
    func loginOut(code:Int) -> Bool
    /// 打印请求数据
    var debugLog: Bool { get }
    /// 后处理
    func processHandle(response:Dictionary<String, Any>) -> Any
}

// MARK: - Moya插件
/// Moya插件
public final class MoyaPlugin: PluginType {
    
    // 请求前处理（如添加全局 headers）不在主线程
    public func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {
//        var request = request
//        request.addValue("Bearer xxx", forHTTPHeaderField: "Authorization")
        
        // 隐藏菊花加载
        let showTarget = target as? RequestAndShow
        showTarget?.showLoading()
        
        // 打印请求数据
        if showTarget?.debugLog == true {
            var logStr = " ------ URL:\(request.url?.description) ------ \n"
            logStr += "请求头: \(request.headers) \n "
            logStr += "请求方式:\(request.method) \n"
            if  request.httpBody != nil {
                let bodyString = String(data: request.httpBody!, encoding: .utf8)
                logStr += "请求体数据：\(bodyString ?? "") \n "
            }
            logStr += " ------  结束  ------ "
            debugLog(logStr)
        }
        
        return request
    }
    
    // 响应后处理（统一状态码拦截）在主线程
    public func process(_ result: Result<Response, MoyaError>, target: TargetType) -> Result<Response, MoyaError> {
        
        // 代理
        let showTarget = target as? RequestAndShow
        // 隐藏菊花加载
        showTarget?.hideLoading()
        
        switch result {
        case .success(let response):
            
            var logStr = " ------ URL返回:\(response.request?.url?.description) ------ \n"
            logStr += "原始数据data:\(response.data) \n"
            
            // 提取状态码和错误信息
            let statusCode = response.statusCode
            let json = try? response.mapJSON() as? [String: Any]
            let code = json?["code"] as? Int ?? 0
            let msg = json?["msg"] as? String ?? "网络错误"
            
            
            
            // 打印请求数据
            if showTarget?.debugLog == true || code != 200 {
                logStr += "解析数据:\(json?.toJSONString() ?? "nil" ) \n"
                debugLog( logStr )
            }
            
            // 登录过期
            if showTarget != nil && showTarget!.loginOut(code: code) {
                let error = MoyaError.statusCode(Response(statusCode: -2, data: response.data ))
                return .failure( error )
            }
            
            
            // 业务状态码 统一拦截逻辑
            if code != 200 {
                
                showTarget?.showErrorMsg(code: code,msg: msg)
                debugLog("网络错误：\(msg)")
                
                let error = MoyaError.statusCode(Response(statusCode: -1, data: response.data ))
                return .failure( error )
            }
            
            // 处理后的JSON
            var processedJson = showTarget?.processHandle(response: json ?? [:]) ?? [:]
            if processedJson is NSNull || (!(processedJson is [String: Any]) && !(processedJson is [Any])) {
                processedJson = [:]
            }
            
            // 将JSON转换为Data，并生成新的Response
            do {
                let data = try JSONSerialization.data(withJSONObject: processedJson, options: [])
                let modifiedResponse = Response(
                    statusCode: response.statusCode,
                    data: data,
                    request: response.request,
                    response: response.response
                )
                return .success(modifiedResponse)
            } catch {
//                let error = NSError(domain: "Network", code: -1, userInfo: [NSLocalizedDescriptionKey: "响应数据转换失败"])
                let error = MoyaError.statusCode(Response(statusCode: -1, data: Data()))
                debugLog("MoyaRequest网络响应数据转换失败") 
                return .failure(error)
            }
            
        case .failure(let error):
            
            var msg = "网络错误"
            
            
            switch error{
            // http错误，除了2xx以外的状态码
            case .statusCode(let response):
                msg = "网络错误:\(response.statusCode)"
                break
            // 底层网络错误
            case .underlying(let err, _):
                
                if let afError = err.asAFError, afError.isExplicitlyCancelledError {
                    debugLog("请求已被主动取消")
                    return .failure(error) // 直接返回不处理提示
                }else if let nsError = err.asAFError?.underlyingError as? NSError {
                    // 网络错误状态码 处理
                    switch nsError.code {
                    case NSURLErrorUnknown,NSURLErrorCancelled,NSURLErrorBadURL:
                        msg = "网络错误:无效的地址!"
                        break
                    case NSURLErrorTimedOut:
                        msg = "网络超时，请稍后再试!"
                        break
                    case NSURLErrorUnsupportedURL:
                        msg = "不支持的地址!"
                        break
                    case NSURLErrorCannotFindHost:
                        msg = "找不到服务器!"
                        break
                    case NSURLErrorCannotConnectToHost:
                        msg = "连接不上服务器!"
                        break
                    case NSURLErrorNetworkConnectionLost:
                        msg = "网络连接异常!"
                        break
                    case NSURLErrorNotConnectedToInternet:
                        msg = "无网络连接!"
                        break
                    default:
                        break
                    }
                }
                break
            default: break
            }
            
            
            if error.errorCode != -2 {
                showTarget?.showErrorMsg(code: error.errorCode,msg: msg)
            }
            
            debugLogFailureError(target: target, msg: msg, error: error)
            
            let err = MoyaError.statusCode(Response(statusCode: -1, data: Data()))
            return .failure( err )
        }
    }
    
    
    
    func debugLogFailureError(target:TargetType,msg:String,error:MoyaError){
        
        var errStr = " ------ 网络错误 ------ \n"
        // 构建URL
        let url = target.baseURL.appendingPathComponent(target.path).absoluteString
        errStr += "URL: \(url) \n"
        // 请求方式
        let method = target.method.rawValue
        errStr += "请求方式: \(method) \n"
        // 请求头
        let headers = target.headers ?? [:]
        errStr += "请求头: \(headers) \n"
        // 请求体数据
        var bodyString = ""
        switch target.task {
        case .requestParameters(let parameters, _):
            if let data = try? JSONSerialization.data(withJSONObject: parameters, options: []),
               let string = String(data: data, encoding: .utf8) {
                bodyString = string
            }
        case .requestData(let data):
            bodyString = String(data: data, encoding: .utf8) ?? ""
        default:
            break
        }
        if !bodyString.isEmpty {
            errStr += "请求体：\(bodyString) \n"
        }
        errStr += "\(msg)-\(error.errorCode):\(error.errorDescription ?? "") \n"
        errStr += " ------ 错误打印结束 ------ "
        debugLog(errStr)
        
    }
    
    
}




/// 从错误中获取返回结果
public func extractDataFromError(_ error: Error) -> [String: Any]? {
    if case let .underlying(err, response) = error as? MoyaError {
        // 优先从 .underlying 的 response 提取 data
        if let responseData = response?.data {
            return try? response?.mapJSON() as? [String: Any]
        }
        // 递归检查底层错误是否包含 MoyaError.statusCode
        return extractDataFromError(err)
    } else if case let .statusCode(response) = error as? MoyaError {
        // 直接提取 .statusCode 的 data
        return try? response.mapJSON() as? [String: Any]
    }
    return nil
}






// 定义全局可追加的插件数组
nonisolated(unsafe) public var additionalPlugins: [PluginType] = []


// MARK: - Extension MoyaProvider

/// 添加自定初始化设置默认参数

public extension MoyaProvider where Target: TargetType {
    // 定义全局默认的 requestClosure
    public static var defaultRequestClosure: RequestClosure {
        let timeoutInterval: TimeInterval = 20 // 自定义超时时间
        return { (endpoint: Endpoint, done: @escaping RequestResultClosure) in
            do {
                var request = try endpoint.urlRequest()
                request.timeoutInterval = timeoutInterval
                done(.success(request))
            } catch {
                done(.failure(MoyaError.underlying(error, nil)))
            }
        }
    }
    
    // 定义全局默认的插件数组
    public static var defaultPlugins: [PluginType] {
        return [MoyaPlugin()] // 自定义插件 1002
    }
    
    // 自定义初始化方法，设置默认参数
    public static func customProvider() -> MoyaProvider<Target> {
        return MoyaProvider(
            requestClosure: Self.defaultRequestClosure,
            plugins: Self.defaultPlugins + additionalPlugins
        )
    }
    
}


//// 扩展请求方法
//extension Reactive where Base: MoyaProviderType {
//
//
//    /// 统一请求方法
//    /// - Parameters:
//    ///   - target: 请求目标类型
//    ///   - showError: 是否显示错误提示
//    func requestEx(
//        _ target: Base.Target,
//        showError: Bool = true,
//        keyPath: String? = nil,
//        callbackQueue: DispatchQueue? = nil
//    ) -> Single<Any> {
//
//        Single.create { [weak base] single in
//
//            // 错误统一处理
//            func errorHandld(error:Error){
//                let errorStr = (error as? RequestError)?.message ?? "网络失败"
//                if showError {
//                    HUD.showHint(hint: errorStr)
//                }
//                single(.failure(error))
//            }
//
//            let cancellableToken = base?.request(target, callbackQueue: callbackQueue, progress: nil) { result in
//                switch result {
//                case let .success(response):
//
//                    do{
//                        //解析 JSON 数据
//                        let dic = try response.mapJSON() as? [String:Any] ?? [:]
//
//                        // 错误码处理
//                        let code = dic["errorCode"] as? Int ?? 0
//                        if code != 0 || response.statusCode != 200 {
//                            throw RequestError(code: response.statusCode)
//                        }
//
//                        var body = [:]
//                        if dic.keys.contains("body") {
//                            body = dic["body"] as? [String:Any] ?? [:]
//                        }else{
//                            body = dic
//                        }
//
//                        single(.success(body))
//
//                    } catch let error {
//                        // 处理错误
//                        errorHandld(error: error)
//                        // 发送错误消息
//                        single(.failure(error))
//                    }
//
//                // 网络失败
//                case let .failure(error):
//                    // 处理失败
//                    errorHandld(error: error)
//                }
//            }
//
//            return Disposables.create {
//                cancellableToken?.cancel()
//            }
//        }
//    }
//}
